/**
 * Form Validation
 * This must be include Form Internalization Library ./js/i18n/<LANGUAGE>/form.lang.js
 * @autho ReGeDa
 */

(function() {

	// fetch enabled elements
	function getFields(f) {

		var present = {};

		$.foreach(f.elements, function(items, i) {

			var e = items[i];

			if ( ! e.name.empty() && e.type != "submit" && ! e.disabled) {
				// only checked box
				if (e.type == "checkbox")
					present[e.name] = e;
				else if (e.type == "radio") {
					// not defined or checked radio-button
					if (typeof(present[e.name]) == "undefined" || e.checked)
						present[e.name] = e;
				}
				// other inputs
				else
					present[e.name] = e;
			}
		});

		return present;
	}

	// try translate field name
	function getTranslate(fieldName) {
		return CONF.translateFields[fieldName] || fieldName;
	}

	// form query
	var query = [];
	
	// throw validation error
	function throwError(e, ruleName, frmtErrArgs) {
		e.focus();
		throw CONF.messages[ruleName].format(frmtErrArgs);
	}

	// fetch validated query
	function validateQuery(f, rules) {

		var fields = getFields(f);

		try {

			query = [];

			for(var name in fields) {

				// define a field
				var e = fields[name];

				// does rules exist?
				if (typeof(rules[name]) != "undefined") {

					var validators = rules[name].split(/[\s]+:[\s]+/);

					// validate required field
					// "required" rule must be at first of sequence
					if (validators[0] == "required") {

						// verify box checked
						if (e.type == "checkbox" || e.type == "radio") {
							if ( ! e.checked)
								throwError(e, "checked", [getTranslate(e.name)]);
						}
						// verify input value
						else {
							// value trimmer
							e.value = e.value.trim();

							// if empty
							if (e.value.empty())
								throwError(e, "required", [getTranslate(e.name)]);
						}

						//////////////////////// ON SUCCESS
						// remove "required" rule
						validators.shift();

					}
					// skip empty value if it not require
					else if (e.value.empty())
						continue;

					// save parameter option
					var saveParam = true;

					/////////////////////////////// OTHER RULES
					// validate rules
					validators.each(function(ruleName) {

						// get input parameters from rule like "rule[param]""
						// @param [sf]:string
						// s - scalar (integer, string, double)
						// f - field
						var params = ruleName.match(/^(\w+)(\[([sf]):(.+)\])?$/);

						var validatorType = ''; // not set

						// with argument
						if (params[4]) {
							ruleName = params[1];
							validatorType = params[3]; // string|field
						}

						// no query parameter
						if (ruleName == "noQuery") {
							saveParam = false;
							// stop validation
							return true;
						}

						var validatorArgs;
						var frmtErrArgs = [getTranslate(e.name)]; // translated element name

						switch (validatorType) {
							//////////////////////////// with string
							case 's':
								// element, string
								validatorArgs = [e, params[4]];
								// add second argument
								frmtErrArgs.push(params[4]);
								break;
							//////////////////////////// with field
							case 'f':
								// element, element
								validatorArgs = [e, fields[params[4]]];
								// add matched element's name
								frmtErrArgs.push(getTranslate(params[4]));
								break;
							//////////////////////////// only check
							default:
								// element
								validatorArgs = e;
						}

						// validate
						if ( ! CONF.validators[ruleName](validatorArgs))
							throwError(e, ruleName, frmtErrArgs);
						
						return false;
					});

					// not need save it
					if ( ! saveParam)
						continue;
				}

				var val;

				// set a value
				switch (e.type) {
					case "checkbox": val = e.checked.intval(); break;
					case "radio":
						if ( ! e.checked)
							break;
					default:
						val = e.value.encode();
				}

				// save query parameter
				if (val != null)
					query.push(name + '=' + val);
			}

			return true;

		} catch (emsg) {
			// handle a message
			alert(emsg);
			return false;
		}
	}

	// validation settings
	var CONF = {
		// error messages
		messages: jLang.form.validationMessages,
		// translated fields names
		translateFields: {},
		// elements validators
		validators: {
			// check email address
			email: function(e) {
				return $(e).is_email();
			},
			// input test equivalent to form element
			// only works with f: type
			match: function(args) {
				return args[0].value == args[1].value;
			},
			// check max length
			max_len: function(args) {
				return args[0].value.length <= args[1].intval()
			},
			// check max length
			min_len: function(args) {
				return args[0].value.length >= args[1].intval()
			},
			// check max length
			exact_len: function(args) {
				return args[0].value.length == args[1].intval()
			},
			// check a numeric
			numeric: function(e) {
				return /^\d+$/.test(e.value);
			},
			// check by pattern
			pattern: function(args) {
				return new RegExp('^' + args[1] + '$').test(args[0].value);
			},
			// check password strength
			pass_strength: function(e) {
				return $(e).passwdStrength() > 2;
			}
		}
	};

	// Jim Dog plugin FORM
	jClass.extend($, {

		// validate a form by rules
		// @param rules - {fields, validators, messages, translateFields}
		validate: function(rules) {

			rules = rules || {};

			// extends validation config
			["validators","messages","translateFields"].each(function(confName) {
				CONF[confName] = jClass.copy(CONF[confName], rules[confName]);
			});

			// select fields
			if (typeof(rules.fields) != "undefined")
				rules = rules.fields;

			// Go! Go! Go!
			return validateQuery(this.context(), rules);
		},
		// check for correct e-mail value
		is_email: function() {
			return /^([a-z0-9\+_\-]+)(\.[a-z0-9\+_\-]+)*@([a-z0-9\-]+\.)+[a-z]{2,6}$/.test(this.context().value);
		},
		// get query string
		query: function() {
			return query.join('&');
		},
		// calculate password strength
		passwdStrength: function() {
			var s = this.context().value; // password

			if (s.length) {

				var n = 0;

				// calculate string length
				if (s.length > 2 && s.length < 5)
					n += 15;
				else if (s.length > 4 && s.length < 7)
					n += 25;
				else if (s.length > 6)
					n += 40;

				// calculate string content
				if (s.length > 4) {
					if (s.match(/[a-zA-Z]/)) n += 10;
					if (s.match(/([a-z].*[A-Z])|([A-Z].*[a-z])/)) n += 25;
					if (s.match(/([^\d]+\d+)+/)) n += 25;
					if (s.match(/[^a-zA-Z\d]+/)) n += 15;
				}

				// select a level
				if (n < 26) return 1; // very bad
				if (n > 25 && n < 46) return 2; // bad
				if (n > 45 && n < 66) return 3; // good
				if (n > 65 && n < 86) return 4; // very good

				return 5; // excellent
			}
			// empty password
			return 0;
		}
	});

})();

// end of file